﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using System.MessagingCE;

namespace Interfaces
{
    public class MiddlewareServices : IMiddleware, IDisposable
    {
        public bool Enabled { get; set;}
        private MessageDispatcher Dispatcher = new MessageDispatcher();
        public readonly Guid ApplicationId = Guid.NewGuid();
        private Dictionary<Guid, ContextMatchesHandler> contextCallbackDispatcher = new Dictionary<Guid,ContextMatchesHandler>();

        public DateTime LastFixTime { get; private set; }
        public IAbsoluteData LastFixPosition { get; private set; }

        public MiddlewareServices()
        {
            LastFixPosition = new GPSData();

            // TODO: remove this!
            LastFixPosition.Latitude = 47.4753;
            LastFixPosition.Longitude = 19.0558;

            Dispatcher.RegisterMessageWriter("ApplicationEvent");
            Dispatcher.RegisterMessageWriter("MarkerEvent");
            Dispatcher.RegisterMessageWriter("ContextEvent");

            Dispatcher.Send("ApplicationEvent", new ApplicationEventMessage(ApplicationId, ApplicationEventMessage.ApplicationEventArgs.Operation.Attach));
            Dispatcher.RegisterMessageReader("NewAbsoluteDataAvailable_" + this.ApplicationId,
                new EventHandler(OnNewAbsoluteDataAvailable));
            Dispatcher.RegisterMessageReader("NewCellDataAvailable_" + this.ApplicationId,
                new EventHandler(OnNewCellDataAvailable));
        }

        private void OnNewAbsoluteDataAvailable(object sender, EventArgs args)
        {
            if (Enabled)
            {
                SignalEventMessage msg = new SignalEventMessage();
                Dispatcher.Receive("NewAbsoluteDataAvailable_" + this.ApplicationId, msg);
                LastFixTime = DateTime.Now;
                LastFixPosition = (IAbsoluteData)msg.Args.Position[0];
                if (NewAbsoluteDataAvailable != null)
                {
                    NewAbsoluteDataAvailable(sender, msg.Args);
                }
            }
        }

        private void OnNewCellDataAvailable(object sender, EventArgs args)
        {
            if (Enabled)
            {
                SignalEventMessage msg = new SignalEventMessage();
                Dispatcher.Receive("NewCellDataAvailable_" + this.ApplicationId, msg);
                if (NewCellDataAvailable != null)
                {
                    NewCellDataAvailable(sender, msg.Args);
                }
            }
        }

        #region IMiddleware Members

        public event NewAbsoluteDataAvailableHandler NewAbsoluteDataAvailable;

        public event NewCellDataAvailableHandler NewCellDataAvailable;

        public event NewWifiDataAvailableHandler NewWifiDataAvailable;

        public event NewPairedDataAvailableHandler NewPairedDataAvailable;

        public event ContextChangedHandler ContextChanged;

        public int CreateTemplate(System.IO.Stream background, System.Drawing.Point imageOffset, System.Drawing.Point offset, string owner)
        {
            throw new NotImplementedException();
        }

        public int NewMarker(double latitude, double longitude, int proto_id, string text, System.Drawing.Bitmap image)
        {
            throw new NotImplementedException();
        }

        public bool MoveMarker(int marker_id, double latitude, double longitude)
        {
            throw new NotImplementedException();
        }

        public int CreateEvent(string description, short minRelevance, ContextMatchesHandler eventHandler, PositionOriginator[] originators)
        {
            throw new NotImplementedException();
        }

        public int CreateEvent(string description, short minRelevance, ContextMatchesHandler eventHandler, string[] members)
        {
            ContextEventMessage.ContextEventArgs args = new ContextEventMessage.ContextEventArgs(ContextEventMessage.ContextEventArgs.Operation.New);
            args.description = description;
            args.minRelevance = minRelevance;
            args.members = members;
            args.eventHandlerGuid = Guid.NewGuid();

            Dispatcher.Send("ContextEvent", new ContextEventMessage(args));
            contextCallbackDispatcher.Add(args.eventHandlerGuid, eventHandler);

            return 0;
        }

        private void ContextCallbackHandler(object sender, EventArgs args)
        {
            ContextEventMessage msg = new ContextEventMessage();
            Dispatcher.Receive("ContextEventCallback_" + this.ApplicationId, msg);
            if (msg.Args.Op == ContextEventMessage.ContextEventArgs.Operation.Callback
                && contextCallbackDispatcher.ContainsKey(msg.Args.eventHandlerGuid))
            {
                contextCallbackDispatcher[msg.Args.eventHandlerGuid](this, msg.Args.id, msg.Args.minRelevance);
            }
        }

        public bool MergeEvent(int id, string[] members)
        {
            throw new NotImplementedException();
        }

        public bool RemoveEvent(int id)
        {
            throw new NotImplementedException();
        }

        public string[] GetCurrentContext(PositionOriginator[] originators)
        {
            // TODO: send GetCurrentContextMessage, process and respond
            return null;
        }

        #endregion

        #region ICommonInterface Members

        public bool InitSettingsGroup(string app_id)
        {
            throw new NotImplementedException();
        }

        public bool DeleteSettingsGroup(string app_id)
        {
            throw new NotImplementedException();
        }

        public bool SettingsGroupAvailable(string app_id)
        {
            throw new NotImplementedException();
        }

        public bool SetSetting(string app_id, string setting_name, object data)
        {
            throw new NotImplementedException();
        }

        public object GetSetting(string app_id, string setting_name)
        {
            throw new NotImplementedException();
        }

        public bool DeleteSetting(string app_id, string setting_name)
        {
            throw new NotImplementedException();
        }

        public void WriteDebugLog(string s)
        {
            throw new NotImplementedException();
        }

        public string WorkingDirectory
        {
            get { return @"\Application Data\pozr"; }
        }

        #endregion

        public void LockPosition(IAbsoluteData position)
        {
            this.LastFixPosition = position;
            this.Enabled = false;
        }

        #region IDisposable Members

        public void Dispose()
        {
            throw new NotImplementedException();
        }

        #endregion
    }
}
